<!DOCTYPE html><html lang="zh-CN"><head><meta name="generator" content="Hexo 3.8.0"><meta name="google-site-verification" content="wD1H9sqEoDWmIBFt7TjlgbVqcJqiqpwR2Wq7_bvEHcE"><meta name="baidu-site-verification" content="RZErJH3v0Z"><meta charset="utf-8"><link rel="icon" href="/css/images/my_logo.png" type="image/x-icon"><title>SpringBoot完美整合Jfinal | ArtIsLong的博客</title><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="description" content="机缘巧合之下接触到了Jfinal，但是由于个人目前主要的技术栈还是以SpringBoot为主，所以不免得想着将Jfinal与SpringBoot集成到一起去使用。"><meta name="keywords" content="SpringBoot"><meta property="og:type" content="article"><meta property="og:title" content="SpringBoot完美整合Jfinal"><meta property="og:url" content="/2019/07/14/SpringBoot完美整合Jfinal/index.html"><meta property="og:site_name" content="ArtIsLong的博客"><meta property="og:description" content="机缘巧合之下接触到了Jfinal，但是由于个人目前主要的技术栈还是以SpringBoot为主，所以不免得想着将Jfinal与SpringBoot集成到一起去使用。"><meta property="og:locale" content="zh-CN"><meta property="og:image" content="https://artislong.oss-cn-hangzhou.aliyuncs.com/images/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B71.png"><meta property="og:updated_time" content="2019-08-04T10:49:57.252Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="SpringBoot完美整合Jfinal"><meta name="twitter:description" content="机缘巧合之下接触到了Jfinal，但是由于个人目前主要的技术栈还是以SpringBoot为主，所以不免得想着将Jfinal与SpringBoot集成到一起去使用。"><meta name="twitter:image" content="https://artislong.oss-cn-hangzhou.aliyuncs.com/images/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B71.png"><link rel="alternate" href="/atom.xml" title="ArtIsLong的博客" type="application/atom+xml"><link rel="stylesheet" href="/libs/font-awesome5/css/fontawesome.min.css"><link rel="stylesheet" href="/libs/font-awesome5/css/fa-brands.min.css"><link rel="stylesheet" href="/libs/font-awesome5/css/fa-solid.min.css"><link rel="stylesheet" href="/libs/open-sans/styles.css"><link rel="stylesheet" href="/libs/source-code-pro/styles.css"><link rel="stylesheet" href="/css/style.css"><script src="/libs/jquery/2.1.3/jquery.min.js"></script><link rel="stylesheet" href="/libs/lightgallery/css/lightgallery.min.css"><link rel="stylesheet" href="/libs/justified-gallery/justifiedGallery.min.css"><script>var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="//hm.baidu.com/hm.js?b59777544dd5d59ce94e191bac62427c";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script><script>(adsbygoogle=window.adsbygoogle||[]).push({google_ad_client:"ca-pub-4444107320537106",enable_page_level_ads:!0})</script></head></html><body><div id="container"><header id="header"><div id="header-main" class="header-inner"><div class="outer"><a href="/" id="logo"><i class="logo"></i> <span class="site-title">ArtIsLong的博客</span></a><nav id="main-nav"> <a class="main-nav-link" href="/.">首页</a> <a class="main-nav-link" href="/archives">归档</a> <a class="main-nav-link" href="/books">书架</a> <a class="main-nav-link" href="/about">关于我</a></nav><nav id="sub-nav"><div class="profile" id="profile-nav"> <a id="profile-anchor" href="javascript:;"><img class="avatar" src="/css/images/head.png"><i class="fas fa-caret-down"></i></a></div></nav><div id="search-form-wrap"><form class="search-form"> <input type="text" class="ins-search-input search-form-input" placeholder="搜索"> <button type="submit" class="search-form-submit"></button></form><div class="ins-search"><div class="ins-search-mask"></div><div class="ins-search-container"><div class="ins-input-wrapper"> <input type="text" class="ins-search-input" placeholder="想要查找什么..."><span class="ins-close ins-selectable"><i class="fas fa-times-circle"></i></span></div><div class="ins-section-wrapper"><div class="ins-section-container"></div></div></div></div><script>window.INSIGHT_CONFIG={TRANSLATION:{POSTS:"文章",PAGES:"页面",CATEGORIES:"分类",TAGS:"标签",UNTITLED:"(未命名)"},ROOT_URL:"/",CONTENT_URL:"/content.json"}</script><script src="/js/insight.js"></script></div></div></div><div id="main-nav-mobile" class="header-sub header-inner"><table class="menu outer"><tr><td><a class="main-nav-link" href="/.">首页</a></td><td><a class="main-nav-link" href="/archives">归档</a></td><td><a class="main-nav-link" href="/books">书架</a></td><td><a class="main-nav-link" href="/about">关于我</a></td><td><div class="search-form"> <input type="text" class="ins-search-input search-form-input" placeholder="搜索"></div></td></tr></table></div></header><div class="outer"><aside id="profile" class="profile-fixed"><div class="inner profile-inner"><div class="base-info profile-block"> <a href="/"><img id="avatar" src="/css/images/head.png"></a><h2 id="name">ArtIsLong</h2><h3 id="title">不吹牛，不装逼，只做最单纯的技术分享</h3><span id="location"><i class="fas fa-map-marker-alt" style="padding-right:5px"></i> Shanghai, China</span> <a id="follow" target="_blank" href="https://github.com/ArtIsLong">关注我</a></div><div class="article-info profile-block"><div class="article-info-block"> 39 <span>文章</span></div><div class="article-info-block"> 30 <span>标签</span></div></div><div class="profile-block social-links"><table><tr><td><a href="http://github.com/ArtIsLong" target="_blank" title="Github" class="tooltip"><i class="fab fa-github"></i></a></td><td> <a href="https://gitee.com/artislong" target="_blank" title="Gitee" class="tooltip"><i class="fab"><img src="https://gitee.com/artislong/artislong/widgets/widget_5.svg" style="height:25px;margin-bottom:-5px"></i></a></td><td> <a href="https://www.jianshu.com/u/46d989a94f20" target="_blank" title="简书" class="tooltip"><i class="fab"><span style="height:25px;margin-bottom:-5px;color:#ff8c00">简</span></i></a></td><td> <a href="mailto:chenmin049@163.com" target="_blank" title="E-Mail" class="tooltip"><i class="fab"><span style="height:25px;width:20px;margin-bottom:-5px;color:#1e90ff;font-size:16px">Mail</span></i></a></td><td><a href="/atom.xml" target="_blank" title="RSS" class="tooltip"><i class="fas fa-rss"></i></a></td></tr></table></div></div></aside><section id="main"><article id="post-SpringBoot完美整合Jfinal" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 class="article-title" itemprop="name"> SpringBoot完美整合Jfinal</h1><div class="article-meta"><div class="article-date"><i class="fas fa-calendar-alt"></i> <a href="/2019/07/14/SpringBoot完美整合Jfinal/"><time datetime="2019-07-14T15:32:31.000Z" itemprop="datePublished">2019-07-14 23:32:31</time></a></div><div class="article-category"><i class="fas fa-folder"></i> <a class="article-category-link" href="/categories/SpringBoot/">SpringBoot</a></div><div class="article-tag"><i class="fas fa-tag"></i> <a class="tag-link" href="/tags/SpringBoot/">SpringBoot</a></div><div style="font-size:12px"><span id="busuanzi_container_page_pv">阅读次数：<span id="busuanzi_value_page_pv"></span></span></div></div></header><div class="article-entry" itemprop="articleBody"><div id="toc" class="toc-article"> <strong class="toc-title">文章目录</strong><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#环境准备"><span class="toc-number">1.</span> <span class="toc-text">环境准备</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#集成方案"><span class="toc-number">2.</span> <span class="toc-text">集成方案</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#SpringBoot与Jfinal浅集成"><span class="toc-number">2.1.</span> <span class="toc-text">SpringBoot与Jfinal浅集成</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#SpringBoot与Jfinal深度集成"><span class="toc-number">2.2.</span> <span class="toc-text">SpringBoot与Jfinal深度集成</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#模仿MyBatis的MapperScan功能"><span class="toc-number">2.2.1.</span> <span class="toc-text">模仿MyBatis的MapperScan功能</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#自定义Jfinal数据源配置Plugins"><span class="toc-number">2.2.2.</span> <span class="toc-text">自定义Jfinal数据源配置Plugins</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JFinal-SQL模板路径配置化"><span class="toc-number">2.2.3.</span> <span class="toc-text">JFinal SQL模板路径配置化</span></a></li></ol></li></ol></li></ol></div><p>机缘巧合之下接触到了<a href="https://www.jfinal.com/" target="_blank" rel="noopener">Jfinal</a>，但是由于个人目前主要的技术栈还是以SpringBoot为主，所以不免得想着将Jfinal与SpringBoot集成到一起去使用。<a id="more"></a></p><h1 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h1><p>引入SpringBoot、Jfinal等相关配置</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.1.6.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">relativePath</span>/&gt;</span> <span class="comment">&lt;!-- lookup parent from repository --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.jfinal<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jfinal<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.1.47<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-jdbc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-configuration-processor<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure><h1 id="集成方案"><a href="#集成方案" class="headerlink" title="集成方案"></a>集成方案</h1><p>使用SpringBoot集成Jfinal有两种方案:</p><ol><li>使用SpringBoot管理Jfinal的Filter，即通过SpringBoot去构造Jfinal服务，Jfinal的正常运行不需要SpringBoot的参与。此种方式可以称之为浅集成</li><li>使用SpringBoot管理Jfinal的Routes、Controller、Interceptor等，SpringBoot与Jfinal混合交叉使用，即在Jfinal的Bean中，可使用SpringBoot的其他Bean。可称之为深度集成。</li></ol><p><strong>注：</strong> Jfinal和SpringBoot的项目搭建不做介绍，读者可自行学习。</p><h2 id="SpringBoot与Jfinal浅集成"><a href="#SpringBoot与Jfinal浅集成" class="headerlink" title="SpringBoot与Jfinal浅集成"></a>SpringBoot与Jfinal浅集成</h2><p>编写SpringJFinalFilter过滤器</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringJFinalFilter</span> <span class="keyword">implements</span> <span class="title">Filter</span> </span>&#123;</span><br><span class="line">	<span class="keyword">private</span> Filter jfinalFilter;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException </span>&#123;</span><br><span class="line">		jfinalFilter = createJFinalFilter(<span class="string">"com.jfinal.core.JFinalFilter"</span>);</span><br><span class="line">		jfinalFilter.init(filterConfig);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doFilter</span><span class="params">(ServletRequest request, ServletResponse response, FilterChain chain)</span> <span class="keyword">throws</span> IOException,</span></span><br><span class="line"><span class="function">			ServletException </span>&#123;</span><br><span class="line">		jfinalFilter.doFilter(request, response, chain);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">destroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		jfinalFilter.destroy();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="function"><span class="keyword">private</span> Filter <span class="title">createJFinalFilter</span><span class="params">(String filterClass)</span> </span>&#123;</span><br><span class="line">		Object temp = <span class="keyword">null</span>;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			temp = Class.forName(filterClass).newInstance();</span><br><span class="line">		&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"Can not create instance of class: "</span> + filterClass, e);</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (temp <span class="keyword">instanceof</span> Filter) &#123;</span><br><span class="line">			<span class="keyword">return</span> (Filter) temp;</span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"Can not create instance of class: "</span> + filterClass + <span class="string">"."</span>);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>配置Filter</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> FilterRegistrationBean <span class="title">filterRegistrationBean</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  FilterRegistrationBean filterRegistrationBean = <span class="keyword">new</span> FilterRegistrationBean();</span><br><span class="line">  filterRegistrationBean.setFilter(<span class="keyword">new</span> SpringJFinalFilter());</span><br><span class="line">  filterRegistrationBean.addUrlPatterns(<span class="string">"/*"</span>);</span><br><span class="line">  <span class="keyword">return</span> filterRegistrationBean;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>其他使用Jfinal原生配置，不需要掺杂SpringBoot的任何配置项，即可由SpringBoot启动Jfinal应用。此种方式简单明了，但是可用性不高，虽然Jfinal依赖于SpringBoot在运行，但是两个框架由互相独立，未做到交叉使用。故需要接下来的SpringBoot与Jfinal的深度集成。</p><h2 id="SpringBoot与Jfinal深度集成"><a href="#SpringBoot与Jfinal深度集成" class="headerlink" title="SpringBoot与Jfinal深度集成"></a>SpringBoot与Jfinal深度集成</h2><p>SpringBoot与Jfinal的深度集成，将SpringBoot的Routes、Controller、Interceptor作为Spring的Bean来处理，以便与SpringBoot以及其他框架交叉使用，来满足不同的需求。</p><p>如果使用Jfinal来开发后台REST接口，需要以下步骤：</p><ol><li><p>创建自定义Controller类，并继承com.jfinal.core.Controller，然后在其中编写方法，方法名就是请求路径。</p></li><li><p>创建自定义Routes类，并继承com.jfinal.config.Routes，然后通过add方法，加载自定义Controller，并设置路由路径。</p><p>如：<code>add(&quot;/admin&quot;, AdminController.clas)</code></p></li><li><p>然后通过com.jfinal.config.JFinalConfig的configRoute(Routes me)方法，加载自定义路由类。</p></li><li><p>配置数据源。虽然Jfinal提供了c3p0，druid，hikaricp等数据源配置插件，但是由于我们使用到了SpringBoot，没有必要去契合Jfinal内置的数据源插件了，我们自定义数据源插件，从Spring上下文中接收DataSource即可。</p></li><li><p>配置SQL模板路径。SpringBoot项目线上运行时，基本采用的是jar包方式运行，通过classpath，去获取文件的相对路径获取SQL模板，在打成jar包之后会报找不到对应的文件的错误，所以需要改成以流的方式加载SQL模板。</p></li></ol><h3 id="模仿MyBatis的MapperScan功能"><a href="#模仿MyBatis的MapperScan功能" class="headerlink" title="模仿MyBatis的MapperScan功能"></a>模仿MyBatis的MapperScan功能</h3><p>新建两个注解：</p><p>BeanScan.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在指定包下扫面标志类,将其加载到Spring上下文中</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> chenmin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</span><br><span class="line"><span class="meta">@Target</span>(ElementType.TYPE)</span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Import</span>(JfinalControlScannerRegistrar.class)</span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> BeanScan &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 包扫描路径(不填时从当前路径下扫描)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    String[] basePackages() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    Class&lt;?&gt;[] basePackageClasses() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    Class&lt;? extends BeanNameGenerator&gt; nameGenerator() <span class="keyword">default</span> BeanNameGenerator.class;</span><br><span class="line"></span><br><span class="line">    Class&lt;? extends Annotation&gt; annotationClass() <span class="keyword">default</span> Annotation.class;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 标识类列表</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Class&lt;?&gt;[] markerInterfaces() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>RouterPath.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 定义Jfinal Controller路由</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> chenmin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Target</span>(&#123;ElementType.TYPE&#125;)</span><br><span class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Inherited</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> RouterPath &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 路由值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">String <span class="title">value</span><span class="params">()</span> <span class="keyword">default</span> ""</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>既然已经有现有框架有这种功能了，那我们直接去看MyBatis的源码，快速了解MyBatis的源码的同时还能熟悉Spring的源码呢。</p><p>在MyBatis的MapperScan注解所在包中，存在三个关键类：<code>ClassPathMapperScanner</code>,<code>MapperScannerRegistrar</code>,<code>MapperScannerConfigurer</code>。其中<code>MapperScannerConfigurer</code>配置类是为了整合Spring和MyBatis所存在的，我们不去关注它。我们重点看另外两个类，参考它们实现我们自定义的工具，MyBatis的源码不做解释，因为原理类似，在实现自定义工具时，会顺带着讲解这部分原理。</p><p><code>ClassPathMapperScanner</code>的父类ClassPathBeanDefinitionScanner，它的作用就是将指定包下的类通过一定规则过滤后 将Class 信息包装成 BeanDefinition 的形式注册到IOC容器中。</p><p><code>MapperScannerRegistrar</code>的ImportBeanDefinitionRegistrar接口不是直接注册Bean到IOC容器，它的执行时机比较早，准确的说更像是注册Bean的定义信息以便后面的Bean的创建。</p><p>BeanScan.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在指定包下扫面标志类,将其加载到Spring上下文中</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> chenmin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</span><br><span class="line"><span class="meta">@Target</span>(ElementType.TYPE)</span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Import</span>(JfinalControlScannerRegistrar.class)</span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> BeanScan &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 包扫描路径(不填时从当前路径下扫描)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    String[] basePackages() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">    Class&lt;? extends BeanNameGenerator&gt; nameGenerator() <span class="keyword">default</span> BeanNameGenerator.class;</span><br><span class="line">    Class&lt;? extends Annotation&gt; annotationClass() <span class="keyword">default</span> Annotation.class;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 标识类</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Class&lt;?&gt;[] markerInterfaces() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>RouterPath.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 定义Jfinal Controller路由</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> chenmin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Target</span>(&#123;ElementType.TYPE&#125;)</span><br><span class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Inherited</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> RouterPath &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 路由值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">String <span class="title">value</span><span class="params">()</span> <span class="keyword">default</span> ""</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>ClassPathJfinalControlScanner.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf</span>4j</span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@Accessors</span>(chain = <span class="keyword">true</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassPathJfinalControlScanner</span> <span class="keyword">extends</span> <span class="title">ClassPathBeanDefinitionScanner</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Class&lt;? extends Annotation&gt; annotationClass;</span><br><span class="line">    <span class="keyword">private</span> Class&lt;?&gt;[] markerInterfaces;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ClassPathJfinalControlScanner</span><span class="params">(BeanDefinitionRegistry registry)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(registry, <span class="keyword">false</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 配置扫描接口</span></span><br><span class="line"><span class="comment">     * 扫描添加了markerInterfaces标志类的类或标注了annotationClass注解的类,</span></span><br><span class="line"><span class="comment">     * 或者扫描所有类</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">  	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerFilters</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.annotationClass != <span class="keyword">null</span>) &#123;</span><br><span class="line">            addIncludeFilter(<span class="keyword">new</span> AnnotationTypeFilter(<span class="keyword">this</span>.annotationClass));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.markerInterfaces != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (Class&lt;?&gt; markerInterface : markerInterfaces) &#123;</span><br><span class="line">                addIncludeFilter(<span class="keyword">new</span> AssignableTypeFilter(markerInterface));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重写ClassPathBeanDefinitionScanner的doScan方法,以便在我们自己的逻辑中调用</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> basePackages</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> Set&lt;BeanDefinitionHolder&gt; <span class="title">doScan</span><span class="params">(String... basePackages)</span> </span>&#123;</span><br><span class="line">        Set&lt;BeanDefinitionHolder&gt; beanDefinitions = <span class="keyword">super</span>.doScan(basePackages);</span><br><span class="line">        <span class="keyword">if</span> (beanDefinitions.isEmpty()) &#123;</span><br><span class="line">            log.warn(<span class="string">"No Jfinal Controller was found in '"</span> + Arrays.toString(basePackages) + <span class="string">"' package. Please check your configuration."</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> beanDefinitions;</span><br><span class="line">    &#125;</span><br><span class="line">	  <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 判断bean是否满足条件,可以被加载到Spring中,markerInterfaces标志类功能再此处实现</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> beanDefinition</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true: 可以被加载到Spring中</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">isCandidateComponent</span><span class="params">(AnnotatedBeanDefinition beanDefinition)</span> </span>&#123;</span><br><span class="line">        Boolean flag = <span class="keyword">false</span>;</span><br><span class="line">        <span class="keyword">for</span> (Class&lt;?&gt; markerInterface : markerInterfaces) &#123;</span><br><span class="line">            flag = markerInterface.getName().equals(beanDefinition.getMetadata().getSuperClassName());</span><br><span class="line">            <span class="keyword">if</span> (!flag) &#123;</span><br><span class="line">                String[] interfaceNames = beanDefinition.getMetadata().getInterfaceNames();</span><br><span class="line">                <span class="keyword">for</span> (String interfaceName : interfaceNames) &#123;</span><br><span class="line">                    flag = markerInterface.getName().equals(interfaceName);</span><br><span class="line">                    <span class="keyword">if</span> (flag) &#123;</span><br><span class="line">                        <span class="keyword">return</span> flag;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (flag) &#123;</span><br><span class="line">                <span class="keyword">return</span> flag;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> flag;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>JfinalControlScannerRegistrar.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf</span>4j</span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@Accessors</span>(chain = <span class="keyword">true</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JfinalControlScannerRegistrar</span> <span class="keyword">implements</span> <span class="title">ImportBeanDefinitionRegistrar</span>, <span class="title">ResourceLoaderAware</span>, <span class="title">EnvironmentAware</span>, <span class="title">BeanFactoryAware</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> ResourceLoader resourceLoader;</span><br><span class="line">    <span class="keyword">private</span> Environment environment;</span><br><span class="line">    <span class="keyword">private</span> BeanFactory beanFactory;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerBeanDefinitions</span><span class="params">(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)</span> </span>&#123;</span><br><span class="line">        AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(BeanScan.class.getName()));</span><br><span class="line">        ClassPathJfinalControlScanner scanner = <span class="keyword">new</span> ClassPathJfinalControlScanner(registry);</span><br><span class="line">        <span class="comment">// this check is needed in Spring 3.1</span></span><br><span class="line">        <span class="keyword">if</span> (resourceLoader != <span class="keyword">null</span>) &#123;</span><br><span class="line">            scanner.setResourceLoader(resourceLoader);</span><br><span class="line">        &#125;</span><br><span class="line">        Class&lt;? extends Annotation&gt; annotationClass = annoAttrs.getClass(<span class="string">"annotationClass"</span>);</span><br><span class="line">        <span class="keyword">if</span> (!Annotation.class.equals(annotationClass)) &#123;</span><br><span class="line">            scanner.setAnnotationClass(annotationClass);</span><br><span class="line">        &#125;</span><br><span class="line">        Class&lt;?&gt;[] markerInterfaces = annoAttrs.getClassArray(<span class="string">"markerInterfaces"</span>);</span><br><span class="line">        <span class="keyword">if</span> (!Class.class.equals(markerInterfaces)) &#123;</span><br><span class="line">            scanner.setMarkerInterfaces(markerInterfaces);</span><br><span class="line">        &#125;</span><br><span class="line">        Class&lt;? extends BeanNameGenerator&gt; generatorClass = annoAttrs.getClass(<span class="string">"nameGenerator"</span>);</span><br><span class="line">        <span class="keyword">if</span> (!BeanNameGenerator.class.equals(generatorClass)) &#123;</span><br><span class="line">            scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));</span><br><span class="line">        &#125;</span><br><span class="line">        List&lt;String&gt; packages = <span class="keyword">new</span> ArrayList&lt;String&gt;();</span><br><span class="line">        String[] basePackages = annoAttrs.getStringArray(<span class="string">"basePackages"</span>);</span><br><span class="line">        <span class="keyword">if</span> (ObjectUtils.isEmpty(basePackages)) &#123;</span><br><span class="line">            packages.addAll(AutoConfigurationPackages.get(<span class="keyword">this</span>.beanFactory));</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            packages.addAll(Arrays.asList(basePackages));</span><br><span class="line">        &#125;</span><br><span class="line">        scanner.registerFilters();</span><br><span class="line">        scanner.doScan(StringUtils.toStringArray(packages));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>工具写好之后，将自定义的RouterPath注解标注到Controller上，value为controller路由。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RouterPath</span>(<span class="string">"/achievement"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AdminAchievementController</span> <span class="keyword">extends</span> <span class="title">Controller</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">index</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    renderJson(<span class="string">"Hello"</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>新建DefaultRouter.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 通过applicationContext.getBeansOfType(Controller.class)获取所有Jfinal的Controller，并获取对应	* <span class="doctag">@RouterPath</span>注解值</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DefaultRouter</span> <span class="keyword">extends</span> <span class="title">Routes</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> ApplicationContext applicationContext;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> DefaultInterceptor interceptor;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">config</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        addInterceptor(interceptor);</span><br><span class="line">        Map&lt;String, Controller&gt; controllerMap = applicationContext.getBeansOfType(Controller.class);</span><br><span class="line">        <span class="keyword">if</span> (!ObjectUtils.isEmpty(controllerMap)) &#123;</span><br><span class="line">            controllerMap.values().forEach(controller -&gt; &#123;</span><br><span class="line">                String value = <span class="string">""</span>;</span><br><span class="line">                RouterPath annotation = controller.getClass().getAnnotation(RouterPath.class);</span><br><span class="line">                <span class="keyword">if</span> (!ObjectUtils.isEmpty(annotation)) &#123;</span><br><span class="line">                    value = annotation.value();</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (ObjectUtils.isEmpty(value)) &#123;</span><br><span class="line">                    String simpleName = controller.getClass().getSimpleName();</span><br><span class="line">                    value = simpleName.substring(<span class="number">0</span>, <span class="number">1</span>).toLowerCase() + simpleName.substring(<span class="number">1</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                add(value, controller.getClass());</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="自定义Jfinal数据源配置Plugins"><a href="#自定义Jfinal数据源配置Plugins" class="headerlink" title="自定义Jfinal数据源配置Plugins"></a>自定义Jfinal数据源配置Plugins</h3><p>新建SpringDataSourceCpPlugin.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 自定义Jfinal DataSourcePlugin,从Spring上下文中注入DataSource,不需要自己去获取数据源属性定义数据源</span></span><br><span class="line"><span class="comment"> * 了.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@Accessors</span>(chain = <span class="keyword">true</span>)</span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringDataSourceCpPlugin</span> <span class="keyword">implements</span> <span class="title">IPlugin</span>, <span class="title">IDataSourceProvider</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> DataSource dataSource;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">start</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (ObjectUtils.isEmpty(dataSource)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">stop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (dataSource != <span class="keyword">null</span>) &#123;</span><br><span class="line">            dataSource = <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后通过JFinalConfig的configPlugin方法，将自定义的数据源Plugin加入进去。</p><h3 id="JFinal-SQL模板路径配置化"><a href="#JFinal-SQL模板路径配置化" class="headerlink" title="JFinal SQL模板路径配置化"></a>JFinal SQL模板路径配置化</h3><p>在application.yml中添加配置项：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">jfinal:</span></span><br><span class="line"><span class="attr">  template:</span> <span class="attr">classpath:template/*/*.sql</span></span><br></pre></td></tr></table></figure><p>加载SQL模板文件(只贴出来了关键代码)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">getSqlTemplates</span><span class="params">(ActiveRecordPlugin arp)</span> </span>&#123;</span><br><span class="line">  ResourcePatternResolver resourceResolver = <span class="keyword">new</span> PathMatchingResourcePatternResolver();</span><br><span class="line">  List&lt;Resource&gt; resources = <span class="keyword">new</span> ArrayList&lt;Resource&gt;();</span><br><span class="line">  String template = <span class="keyword">this</span>.jfinalProperties.getTemplate();</span><br><span class="line">  <span class="keyword">if</span> (template != <span class="keyword">null</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      Resource[] sqlTemplates = resourceResolver.getResources(template);</span><br><span class="line">      resources.addAll(Arrays.asList(sqlTemplates));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">      <span class="comment">// ignore</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  resources.forEach(resource -&gt; &#123;</span><br><span class="line">    StringBuilder content = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      content = getContentByStream(resource.getInputStream());</span><br><span class="line">      arp.addSqlTemplate(<span class="keyword">new</span> StringSource(content, <span class="keyword">true</span>));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">private</span> StringBuilder <span class="title">getContentByStream</span><span class="params">(InputStream inputStream)</span> </span>&#123;</span><br><span class="line">  StringBuilder stringBuilder = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    BufferedReader br = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(inputStream, <span class="string">"UTF-8"</span>));</span><br><span class="line">    String line;</span><br><span class="line">    <span class="keyword">while</span> ((line = br.readLine()) != <span class="keyword">null</span>) &#123;</span><br><span class="line">      stringBuilder.append(line);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">    e.printStackTrace();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> stringBuilder;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>至此，SpringBoot与Jfinal完美集成到一起，在Jfinal的Bean中也可以正常使用Spring的所有功能。</p><hr><p>关注我的微信公众号：FramePower<br>我会不定期发布相关技术积累，欢迎对技术有追求、志同道合的朋友加入，一起学习成长！</p><hr><p><img src="https://artislong.oss-cn-hangzhou.aliyuncs.com/images/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B71.png" alt="微信公众号"></p><div class="reward"><div class="reward-button">赏 <span class="reward-code"><span class="alipay-code"><img class="alipay-img wdp-appear" src="/css/images/alipay.jpeg"></span> <span class="wechat-code"><img class="wechat-img wdp-appear" src="/css/images/Wechat.jpeg"></span></span></div><p class="reward-notice">如果文章对你有帮助，欢迎点击上方按钮打赏作者</p></div></div><footer class="article-footer"><div class="share-container"><div class="bdsharebuttonbox"> <a href="#" class="bds_more" data-cmd="more">分享到：</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a> <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div></footer></div><nav id="article-nav"> <a href="/2019/06/27/SpringBoot集成Flowable-UI/" id="article-nav-older" class="article-nav-link-wrap"><strong class="article-nav-caption">下一篇</strong><div class="article-nav-title">SpringBoot集成Flowable UI</div></a></nav></article><section id="comments"></section></section><aside id="sidebar"><div class="widget-wrap"><h3 class="widget-title">最新文章</h3><div class="widget"><ul id="recent-post" class=""><li><div class="item-thumbnail"><a href="/2019/07/14/SpringBoot完美整合Jfinal/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/SpringBoot/">SpringBoot</a></p><p class="item-title"><a href="/2019/07/14/SpringBoot完美整合Jfinal/" class="title">SpringBoot完美整合Jfinal</a></p><p class="item-date"><time datetime="2019-07-14T15:32:31.000Z" itemprop="datePublished">2019-07-14 23:32:31</time></p></div></li><li><div class="item-thumbnail"><a href="/2019/06/27/SpringBoot集成Flowable-UI/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/工作流/">工作流</a><i class="fas fa-angle-right"></i><a class="article-category-link" href="/categories/工作流/Flowable/">Flowable</a></p><p class="item-title"><a href="/2019/06/27/SpringBoot集成Flowable-UI/" class="title">SpringBoot集成Flowable UI</a></p><p class="item-date"><time datetime="2019-06-26T16:27:21.000Z" itemprop="datePublished">2019-06-27 00:27:21</time></p></div></li><li><div class="item-thumbnail"><a href="/2019/05/25/Flowable五个引擎及相关服务总结/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/工作流/">工作流</a><i class="fas fa-angle-right"></i><a class="article-category-link" href="/categories/工作流/Flowable/">Flowable</a></p><p class="item-title"><a href="/2019/05/25/Flowable五个引擎及相关服务总结/" class="title">Flowable五个引擎及相关服务总结</a></p><p class="item-date"><time datetime="2019-05-25T15:43:07.000Z" itemprop="datePublished">2019-05-25 23:43:07</time></p></div></li><li><div class="item-thumbnail"><a href="/2019/03/01/微服务基础概念认知总结/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/思考/">思考</a></p><p class="item-title"><a href="/2019/03/01/微服务基础概念认知总结/" class="title">微服务基础概念认知总结</a></p><p class="item-date"><time datetime="2019-03-01T15:17:33.000Z" itemprop="datePublished">2019-03-01 23:17:33</time></p></div></li><li><div class="item-thumbnail"><a href="/2019/03/01/Oracle-SQL优化总结/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/Oracle/">Oracle</a></p><p class="item-title"><a href="/2019/03/01/Oracle-SQL优化总结/" class="title">Oracle SQL优化总结</a></p><p class="item-date"><time datetime="2019-03-01T07:30:47.000Z" itemprop="datePublished">2019-03-01 15:30:47</time></p></div></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">分类</h3><div class="widget"><ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Alibaba/">Alibaba</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Docker/">Docker</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Git/">Git</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java基础/">Java基础</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Nginx/">Nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Oracle/">Oracle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Redis/">Redis</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Shiro/">Shiro</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Spring/">Spring</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/SpringBoot/">SpringBoot</a><span class="category-list-count">7</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/SpringBoot/Shiro/">Shiro</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Storm/">Storm</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Tomcat/">Tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Zookeeper/">Zookeeper</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/工作流/">工作流</a><span class="category-list-count">3</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/工作流/Activiti/">Activiti</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/工作流/Flowable/">Flowable</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/工具/">工具</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/开发工具框架/">开发工具框架</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/思考/">思考</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/服务器/">服务器</a><span class="category-list-count">1</span></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">归档</h3><div class="widget"><ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/07/">七月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/06/">六月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/05/">五月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/03/">三月 2019</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/02/">二月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/01/">一月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/12/">十二月 2018</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/11/">十一月 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/08/">八月 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/07/">七月 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/03/">三月 2018</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/02/">二月 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/01/">一月 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/12/">十二月 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/10/">十月 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/09/">九月 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/06/">六月 2017</a><span class="archive-list-count">7</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/12/">十二月 2016</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/07/">七月 2016</a><span class="archive-list-count">1</span></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">标签</h3><div class="widget"><ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Alibaba/">Alibaba</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Docker/">Docker</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Git/">Git</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Idea/">Idea</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Jackson/">Jackson</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java基础/">Java基础</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Lombok/">Lombok</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Nginx/">Nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Oracle/">Oracle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Quartz/">Quartz</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Redis/">Redis</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Session/">Session</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Shiro/">Shiro</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spring/">Spring</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/SpringBoot/">SpringBoot</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Storm/">Storm</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Swagger/">Swagger</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Tomcat/">Tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Zookeeper/">Zookeeper</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/前后端分离/">前后端分离</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/多数据源/">多数据源</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/工作流/">工作流</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/工具/">工具</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/开发工具框架/">开发工具框架</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/微服务/">微服务</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据库/">数据库</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/负载均衡/">负载均衡</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/集群/">集群</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/面试题/">面试题</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/项目架构/">项目架构</a><span class="tag-list-count">2</span></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">标签云</h3><div class="widget tagcloud"> <a href="/tags/Alibaba/" style="font-size:10px">Alibaba</a> <a href="/tags/Docker/" style="font-size:15px">Docker</a> <a href="/tags/Git/" style="font-size:10px">Git</a> <a href="/tags/Idea/" style="font-size:10px">Idea</a> <a href="/tags/Jackson/" style="font-size:10px">Jackson</a> <a href="/tags/Java基础/" style="font-size:17.5px">Java基础</a> <a href="/tags/Lombok/" style="font-size:10px">Lombok</a> <a href="/tags/Nginx/" style="font-size:15px">Nginx</a> <a href="/tags/Oracle/" style="font-size:10px">Oracle</a> <a href="/tags/Quartz/" style="font-size:10px">Quartz</a> <a href="/tags/Redis/" style="font-size:12.5px">Redis</a> <a href="/tags/Session/" style="font-size:10px">Session</a> <a href="/tags/Shiro/" style="font-size:12.5px">Shiro</a> <a href="/tags/Spring/" style="font-size:12.5px">Spring</a> <a href="/tags/SpringBoot/" style="font-size:20px">SpringBoot</a> <a href="/tags/Storm/" style="font-size:10px">Storm</a> <a href="/tags/Swagger/" style="font-size:12.5px">Swagger</a> <a href="/tags/Tomcat/" style="font-size:12.5px">Tomcat</a> <a href="/tags/Zookeeper/" style="font-size:10px">Zookeeper</a> <a href="/tags/前后端分离/" style="font-size:10px">前后端分离</a> <a href="/tags/多数据源/" style="font-size:10px">多数据源</a> <a href="/tags/工作流/" style="font-size:15px">工作流</a> <a href="/tags/工具/" style="font-size:10px">工具</a> <a href="/tags/开发工具框架/" style="font-size:15px">开发工具框架</a> <a href="/tags/微服务/" style="font-size:10px">微服务</a> <a href="/tags/数据库/" style="font-size:10px">数据库</a> <a href="/tags/负载均衡/" style="font-size:10px">负载均衡</a> <a href="/tags/集群/" style="font-size:10px">集群</a> <a href="/tags/面试题/" style="font-size:10px">面试题</a> <a href="/tags/项目架构/" style="font-size:12.5px">项目架构</a></div></div><div class="widget-wrap widget-list"><h3 class="widget-title">链接</h3><div class="widget"><ul><li> <a href="https://www.xiefayang.com">i蝸居年華_谢谢谢</a></li><li> <a href="http://fullsmilespace.com">微笑空间站</a></li></ul></div></div><div id="toTop" class="fas fa-angle-up"></div></aside></div><footer id="footer"><div class="outer"><div id="footer-info" class="inner"> &copy; 2020 ArtIsLong的博客<br> Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>. Theme by <a href="http://github.com/ppoffice">PPOffice</a></div></div><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></footer><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css"><script src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"></script><script>if(document.getElementById("comments")){var id=decodeURI(window.location.pathname),gitalk=new Gitalk({id:id,owner:"ArtIsLong",repo:"ArtIsLong.github.io",admin:["ArtIsLong"],clientID:"2f97f5d71dbb65bf01e1",clientSecret:"f715a8e1507c1fef1c5e3cfaccef8f59aa734318",distractionFreeMode:!0,createIssueManually:!1,perPage:15});gitalk.render("comments")}</script><script src="/libs/lightgallery/js/lightgallery.min.js"></script><script src="/libs/lightgallery/js/lg-thumbnail.min.js"></script><script src="/libs/lightgallery/js/lg-pager.min.js"></script><script src="/libs/lightgallery/js/lg-autoplay.min.js"></script><script src="/libs/lightgallery/js/lg-fullscreen.min.js"></script><script src="/libs/lightgallery/js/lg-zoom.min.js"></script><script src="/libs/lightgallery/js/lg-hash.min.js"></script><script src="/libs/lightgallery/js/lg-share.min.js"></script><script src="/libs/lightgallery/js/lg-video.min.js"></script><script src="/libs/justified-gallery/jquery.justifiedGallery.min.js"></script><script src="/js/main.js"></script></div><script>((window.gitter={}).chat={}).options={room:"artislong/Lobby"}</script><script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer="defer"></script><script type="text/javascript" color="0,0,255" opacity="0.7" zindex="-2" count="99" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script><script async custom-element="amp-auto-ads" src="https://cdn.ampproject.org/v0/amp-auto-ads-0.1.js"></script></body>